/*
 * uart.c
 * $HeadURL: http://bldc-motor.googlecode.com/svn/trunk/Software/usart.c $
 * $Revision: 7 $
 *
 * Created: 29.08.2012 11:21:25
 * $LastChangedDate: 2012-08-30 15:11:54 +0000 (Thu, 30 Aug 2012) $
 *
 *  Author: Jens
 * $Author: boecki91@gmail.com $
 * 
 * File based on 
 * Title:    Interrupt UART library with receive/transmit circular buffers
 * Author:   Peter Fleury <pfleury@gmx.ch>   http://jump.to/fleury
 */

#include <avr/io.h>
#include <avr/interrupt.h>
#include "usart.h"

void USART_init (unsigned int ubrr)
{
	// Anti-interrupt !
	uint8_t sreg = SREG;
	cli();
	
	UBRR0H = (uint8_t) (ubrr>>8);
	UBRR0L = (uint8_t) (ubrr);

	// Switch USART Receiver and Transmitter on and Receive interrupt, too
	
	UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
	UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);

	//Dummy Readout in case of old Data in the Buffer
	do
	{
		UDR0;
	}
	while (UCSR0A & (1 << RXC0));

	// Reset Receive and Transmit Complete-Flags
	UCSR0A = (1 << RXC0) | (1 << TXC0);

	// Restore old Status register
	SREG = sreg;
}
void USART_putc( unsigned char data )
{
	// Take a place in the ringbuffer
	unsigned char tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
	
	//Wait if ring buffer is full
	while ( tmphead == UART_TxTail ){
		;
	}
	// Place data in the ring buffer
	UART_TxBuf[tmphead] = data;
	// Update head adress 
	UART_TxHead = tmphead;
	// Enable Data-Ready interrupt
	UCSR0B |= _BV(UDRIE0);
}
void USART_puts(const char *s )
{
	// Place it all into the buffer one by one
	while (*s)
	{
		USART_putc(*s++);
	}
}
ISR (USART_RX_vect)
{
	uint8_t data = UDR0;
	//Take a place in the ring buffer
	uint8_t tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK;
	
	if ( tmphead == UART_RxTail )
	{
		//ring buffer overflow ignore it
	}
	else
	{
		/* store received data in buffer */
		UART_RxBuf[tmphead] = data;
		/* store new index */
		UART_RxHead = tmphead;
	}
}
unsigned int USART_getc(void)
{
	unsigned char tmptail;
	unsigned char data;

	if ( UART_RxHead == UART_RxTail ) {
		return 0;	/* no data available */
	}
	/* calculate /store buffer index */
	tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK;
	UART_RxTail = tmptail;
	
	/* get data from receive buffer */
	data = UART_RxBuf[tmptail];
	
	return data;
}
ISR (USART_UDRE_vect)
{
	unsigned char tmptail;
	if ( UART_TxHead != UART_TxTail) {
		tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK;
		UART_TxTail = tmptail;
		UDR0 = UART_TxBuf[tmptail];
	}else{
		/* tx buffer empty, disable UDRE interrupt */
		UCSR0B &= ~_BV(UDRIE0);
	}
}

void USART_puti(int16_t integer)
{
	char buffer[10];
	itoa(integer, buffer, 10);
	USART_puts(buffer);
}